package
{

    /**
     * Evolver takes in all the necessary properties to perform and evolution on a Number
     * value.
     *
     * @author jjung
     */
    public class NumberEvolver
    {
        //---------------------------------------------------------------------
        //
        //  Static Variables
        //
        //---------------------------------------------------------------------
        public static const MUTATE_BENE : int = 0;
        public static const MUTATE_DETR : int = 1;
        public static const MUTATE_DC : int = 2;

        //---------------------------------------------------------------------
        //
        //  Variables
        //
        //---------------------------------------------------------------------
        public var max : Number;
        public var min : Number;
        public var maxInc : Number;
        public var maxDec : Number;
        public var interval : Number;
        public var target : Object;
        public var prop : String;

        //---------------------------------------------------------------------
        //
        //  Constructor
        //
        //---------------------------------------------------------------------
        /**
         *  Constructor
         */
        public function NumberEvolver(target : Object, prop : String, maxInc : Number, maxDec : Number, max : Number, min : Number, interval : Number = NaN)
        {
            this.target = target;
            this.prop = prop;

            this.max = max;
            this.min = min;
            this.maxInc = maxInc;
            this.maxDec = maxDec;
            this.interval = interval;
        }

        public function evolve(type : int = MUTATE_DC) : void
        {
            var change : Number = 0;

            switch (type)
            {
                // Mutate between 0 and maxInc
                case MUTATE_BENE:
                    if (isNaN(interval))
                    {
                        change = Math.random() * maxInc;
                    }
                    else
                    {
                        change = Math.round(Math.random() * (maxInc / interval)) * interval;
                    }
                    break;
                // Mutate between maxDec and 0
                case MUTATE_DETR:
                    if (isNaN(interval))
                    {
                        change = Math.random() * maxDec;
                    }
                    else
                    {
                        change = Math.round(Math.random() * Math.abs(maxDec / interval)) * interval;
                    }
                    break;
                // Mutate between maxDec and maxInc
                case MUTATE_DC:
                    if (isNaN(interval))
                    {
                        change = (Math.random() * (maxInc - maxDec)) + maxDec;
                    }
                    else
                    {
                        var range : Number = maxInc - maxDec;

                        change = Math.round(Math.random() * (range / interval)) * interval + maxDec;
                    }
                    break;
            }

            target[prop] += change;

            if (target[prop] > max)
            {
                target[prop] = max;
            }
            else if (target[prop] < min)
            {
                target[prop] = min;
            }
        }
    }
}